#include "FifoEscritura.h"
#include <BaseException.h>
#include <cstring>
#include <errno.h>
#include <sstream>

FifoEscritura::FifoEscritura()
: Fifo(ProjectId::FIFO_ESCRITURA) {
}

FifoEscritura::FifoEscritura(const std::string nombre, const int modoCreacion, const bool protectAccess)
: Fifo(nombre, modoCreacion, ProjectId::FIFO_ESCRITURA, protectAccess) {
}

FifoEscritura::~FifoEscritura() {
}

void FifoEscritura::abrir() {
	if(fd > 0)
		throw BaseException("El fifo ya se encuentra abierto");
	
	fd = open ( m_Nombre.c_str(),O_WRONLY );
	
	if(fd < 0)
	{
		std::stringstream eMsg("Ocurrio un error al abrir el fifo");
		eMsg << "Error " << errno << ":" << strerror(errno);
		throw BaseException(eMsg.str(), errno);
	}
}

void FifoEscritura::escribir(const void* buffer,const ssize_t buffsize) {
	if(fd < 0)
		throw BaseException("El fifo no se encuentra abierto");
	
	ssize_t cantBytesEscritos = 1;
	ssize_t cantBytesRestantes = buffsize;
	const char* bufferAux = static_cast<const char*> (buffer);
	
	while(cantBytesRestantes > 0 && cantBytesEscritos > 0)
	{
		cantBytesEscritos = write ( fd, static_cast<const void*> (bufferAux), cantBytesRestantes );
		if(cantBytesEscritos < 0)
		{
			// Si me interrumpieron, verifico si es para salir o si debo continuar
			if (errno == EINTR && !this->mustExit()) 
				continue;
			std::stringstream eMsg("Ocurrio un error al escribir en el fifo");
			eMsg << "Error " << errno << ":" << strerror(errno);
			throw BaseException(eMsg.str(), errno);
		}
		bufferAux += cantBytesEscritos;
		cantBytesRestantes -= cantBytesEscritos;
		this->incrementarBytesContenidos(cantBytesEscritos);
	}
	
	if(cantBytesRestantes > 0)
		throw BaseException("No se pudo escribir la cantidad de bytes requerida");
}

void FifoEscritura::escribirSincronizado(const void* buffer,const ssize_t buffsize) {
	if(fd < 0)
		throw BaseException("El fifo no se encuentra abierto");
	
	ssize_t cantBytesEscritos = 1;
	ssize_t cantBytesRestantes = buffsize;
	const char* bufferAux = static_cast<const char*> (buffer);
	
	this->lock();
	while(cantBytesRestantes > 0 && cantBytesEscritos > 0)
	{
		cantBytesEscritos = write ( fd, static_cast<const void*> (bufferAux), cantBytesRestantes );
		if(cantBytesEscritos < 0)
		{
			// Si me interrumpieron, verifico si es para salir o si debo continuar
			if (errno == EINTR && !this->mustExit()) 
				continue;
			this->unlock();
			std::stringstream eMsg("Ocurrio un error al escribir en el fifo");
			eMsg << "Error " << errno << ":" << strerror(errno);
			throw BaseException(eMsg.str(), errno);
		}
		bufferAux += cantBytesEscritos;
		cantBytesRestantes -= cantBytesEscritos;
		this->incrementarBytesContenidos(cantBytesEscritos);
	}
	this->unlock();
	
	if(cantBytesRestantes > 0)
		throw BaseException("No se pudo escribir la cantidad de bytes requerida");
}
